package com.beiding.businessplatform.data;

import java.util.*;

/*
    视图模型内部数据缓存
 */
public class VmCache {

    private Vm vm;

    //TODO 标记了内部那些值是有结果的
    private Map<String, CacheUnit> cacheMap;

    public VmCache(Vm vm) {
        this.vm = vm;
        cacheMap = new HashMap<>();
    }

    public void handle(Be be) {
        handle(be, new HashSet<>());
    }

    //外部给定Be进行处理
    void handle(Be be, Set<Vm> vmPath) {
        vm.be(be);
        for (CacheUnit unit : cacheMap.values()) {
            unit.write(vmPath);
        }
    }

    //不给定返回
    Be handle(Set<Vm> vmPath) {
        for (CacheUnit unit : cacheMap.values()) {
            unit.write(vmPath);
        }
        return vm.be();
    }

    //TODO 反射赋值
    public void set(String field, Object value) {
        BaseUnit baseUnit = (BaseUnit) cacheMap.get(field);
        if (baseUnit == null) {
            baseUnit = new BaseUnit(vm, field);
            cacheMap.put(field, baseUnit);
        }
        baseUnit.update(value);
    }

    //TODO
    public void set(String field, Vm value) {
        SubVmUnit vmUnit = (SubVmUnit) cacheMap.get(field);
        if (vmUnit == null) {
            vmUnit = new SubVmUnit(vm, field);
            cacheMap.put(field, vmUnit);
        }
        vmUnit.update(value);
    }

    public void set(String field, List<? extends Vm> value) {
        ListSubVmUnit listSubVmUnit = (ListSubVmUnit) cacheMap.get(field);
        if (listSubVmUnit == null) {
            listSubVmUnit = new ListSubVmUnit(vm, field);
            cacheMap.put(field, listSubVmUnit);
        }
        listSubVmUnit.update(value);
    }


    public Object get(String field) {
        CacheUnit cacheUnit = cacheMap.get(field);
        if (cacheUnit == null) {
            HolderMap o = vm.holderMap();
            Object r = o.get(field).get();
            if (r != null) {
                BaseUnit baseUnit = new BaseUnit(vm, field);
                baseUnit.setValue(r);
                cacheMap.put(field, baseUnit);
                return r;
            } else {
                return null;
            }
        }
        return cacheUnit.read();
    }

    public Vm getVm(String field, Class<? extends Vm> type) {
        CacheUnit cacheUnit = cacheMap.get(field);
        if (cacheUnit == null) {
            HolderMap o = vm.holderMap();

            //内部Be 对象
            Object r = o.get(field).get();
            if (r != null) {
                SubVmUnit baseUnit = new SubVmUnit(vm, field);

                try {
                    Vm vm = type.newInstance();
                    vm.be((Be) r);
                    baseUnit.setSubVm(vm);
                    cacheMap.put(field, baseUnit);
                    return vm;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                return null;
            }
        }
        return (Vm) cacheUnit.read();
    }

    public List getVmList(String field, Class<? extends Vm> type) {
        CacheUnit cacheUnit = cacheMap.get(field);
        if (cacheUnit == null) {
            HolderMap o = vm.holderMap();

            //内部Be 对象
            Object r = o.get(field).get();
            if (r != null) {
                ListSubVmUnit baseUnit = new ListSubVmUnit(vm, field);

                try {

                    List beList= (List) r;

                    List<Vm> list = new ArrayList<>();
                    for (Object be : beList) {
                        Vm vm = type.newInstance();
                        vm.be((Be) be);
                        list.add(vm);
                    }

                    baseUnit.setSubVms(list);

                    cacheMap.put(field, baseUnit);
                    return list;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                return null;
            }
        }
        return (List) cacheUnit.read();
    }

    void update() {
        Set<Vm> vmPath = new HashSet<>();
        for (CacheUnit unit : cacheMap.values()) {
            if (unit instanceof ListSubVmUnit) {
                unit.write(vmPath);
            }
        }
    }
}
